package qc.module.platform.service;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import qc.common.core.constants.QCConstant;
import qc.common.core.enums.ColumnTypeEnum;
import qc.common.core.enums.DataTypeEnum;
import qc.common.core.enums.DataValueOperateTypeEnum;
import qc.common.core.enums.ResourceStatusFlagEnum;
import qc.common.core.exception.QCPromptException;
import qc.common.core.json.JsonParserUtil;
import qc.common.core.utils.DateUtil;
import qc.common.core.utils.JsonUtil;
import qc.common.core.utils.SqlRunnerUtil;
import qc.common.core.utils.StringSplitUtil;
import qc.module.platform.dto.db.DBDto;
import qc.module.platform.dto.dbTable.DBTableDto;
import qc.module.platform.dto.param.group.ParamGroupDto;
import qc.module.platform.dto.param.item.ParamItemDto;
import qc.module.platform.dto.param.log.ParamValueLogDto;
import qc.module.platform.dto.param.log.ParamValueLogQueryConditionDto;
import qc.module.platform.dto.param.log.ParamValueLogQueryResultDto;
import qc.module.platform.dto.param.value.ObjectParamValuesDto;
import qc.module.platform.dto.param.value.ParamValuesGetConditionDto;
import qc.module.platform.dto.param.value.ParamValuesQueryResultDto;
import qc.module.platform.dto.param.value.ParamValuesSaveDto;
import qc.module.platform.entity.QcDbTableColumn;
import qc.module.platform.entity.QcParamItem;
import qc.module.platform.entity.QcParamValueLog;
import qc.module.platform.mapper.ParamItemMapper;
import qc.module.platform.mapper.ParamValueLogMapper;
import qc.module.platform.repository.QcParamGroupRepository;
import qc.module.platform.repository.QcParamItemRepository;
import qc.module.platform.repository.QcParamValueLogRepository;

import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * ParamValueService
 *
 * @author QuCheng Tech
 * @since 2024/2/21
 */
@Service
public class ParamValueService {
    private ParamService paramService;
    private ParamValueLogService paramValueLogService;
    private DbService dbService;
    private DbTableService dbTableService;
    private DbTableColumnService dbTableColumnService;
    
    @Autowired
    private QcParamItemRepository repository;
    
    @Autowired
    private QcParamValueLogRepository paramValueLogRepository;
    
    @Autowired
    private QcParamGroupRepository groupRepository;

    @Autowired
    public void setParamService(ParamService paramService) {
        this.paramService = paramService;
    }

    @Autowired
    public void setParamValueLogService(ParamValueLogService paramValueLogService) {
        this.paramValueLogService = paramValueLogService;
    }

    @Autowired
    public void setDbService(DbService dbService) {
        this.dbService = dbService;
    }

    @Autowired
    public void setDbTableService(DbTableService dbTableService) {
        this.dbTableService = dbTableService;
    }

    @Autowired
    public void setDbTableColumnService(DbTableColumnService dbTableColumnService) {
        this.dbTableColumnService = dbTableColumnService;
    }

    /**
     * 数据库表查询结果中对象ID列名称
     */
    private static final String[] ObjectIdColumnNames = {"id", "Id", "ID", "code", "Code", "CODE"};

    /**
     * 数据库表查询结果中对象名称列名称
     */
    private static final String[] ObjectNameColumnNames = {"name", "Name", "NAME"};

    /**
     * 数据库表查询结果中对象参数值列名称
     */
    private static final String[] ObjectParamColumnNames = {"param", "Param", "PARAM", "params", "Params", "PARAMS"};

    /***
     * 查询指定分组的对象参数值信息
     *
     * @param paramGroupCode 参数分组ID/编码
     * @return qc.module.platform.dto.param.value.ParamValuesQueryResultDto
     * @author QuCheng Tech
     * @since 2024/2/21
     */
    public ParamValuesQueryResultDto queryByGroupId(String paramGroupCode) throws QCPromptException, SQLException {
        /*返回结果中包含信息：参数分组信息、对象集合（对象ID、名称、参数值--键值对）、参数项集合
         *处理逻辑：
         * 1.根据参数分组查询分组信息；
         * 2.1.根据分组ID查询分组中的所有参数项信息；
         * 2.2.根据分组信息中的查询sql语句得到对象集合（包含对象id、对象名称、参数值json）；
         *      根据分组信息中的数据库表，查询数据库列信息--后面取对象id、名称、参数值信息时需要用作数据库列的区分；
         * 3.最终返回结果中需要的参数项集合处理：
         * 3.1.根据分组中的子节点配置，在查询的分组参数项配置中进行匹配
         * 3.2.遍历对象集合，逐个获取分组中子节点下的实际参数值配置；如果不在参数项集合中，添加到参数项集合中（此时没有参数项信息）；
         * 4.返回结果处理：
         * 4.1.分组信息--使用步骤1的结果；
         * 4.2.对象集合--遍历步骤2.2的对象集合；
         *      对象集合--各对象的参数值集合--遍历步骤3得到的参数项集合，从对象参数值json中获取对应参数项的参数值；
         * 4.3.参数项集合--使用步骤3的结果；
         */

        if (StringUtils.isEmpty(paramGroupCode))
            throw new QCPromptException("获取指定参数分组的参数值信息时，参数分组编码不能为空");

        //步骤1
        ParamGroupDto groupDto = paramService.getGroup(paramGroupCode);
        //如果没有分组信息，无法进行后继的信息查询操作
        if (groupDto == null)
            throw new QCPromptException("获取到的参数分组信息为空，输入的参数分组编码错误");
        //如果分组信息中没有查询语句，无法进行对象信息查询
        if (StringUtils.isBlank(groupDto.getQuerysql()))
            throw new QCPromptException("获取到的参数分组信息中查询语句为空，无法进行对象信息和参数值信息查询操作");
        //如果分组信息中没有数据库表编码，无法进行数据库表列信息提取，此时可以使用默认值
        //没有数据库表编码时，无法确定对象表所在的数据库，无法完成对象查询
        if (StringUtils.isBlank(groupDto.getTablecode()))
            throw new QCPromptException("获取到的参数分组信息中数据库表编码为空，无法进行对象信息和参数值信息查询操作");

        //根据数据库表编码获取数据库信息
        DBTableDto tableDto = dbTableService.get(groupDto.getTablecode());
        if (tableDto == null)
            throw new QCPromptException("根据指定的数据库表编码" + groupDto.getTablecode() + "获取到的数据库表信息为空");
        DBDto dbDto = dbService.get(tableDto.getDb());
        if (dbDto == null)
            throw new QCPromptException("根据指定的数据库编码" + tableDto.getDb() + "获取到的数据库信息为空");

        //数据库连接信息
        String dbUrl = "";
        String dbUser = "";
        String dbPassword = "";
        //解析数据库连接信息
        String dbConJsonString = dbDto.getCon();
        if (StringUtils.isNotBlank(dbConJsonString)) {
            //Json对象进行获取
            dbUrl = JsonParserUtil.getString(dbConJsonString, "url");
            dbUser = JsonParserUtil.getString(dbConJsonString, "user");
            dbPassword = JsonParserUtil.getString(dbConJsonString, "password");
        }
        //查询数据库表列信息，传入方法用作分析列名
        List<QcDbTableColumn> tableColumns = dbTableColumnService.getTableColumnEntitys(groupDto.getTablecode(), false,"qrodr");

        //步骤2.1--查询分组中的参数项信息
        List<QcParamItem> groupItems = paramService.getGroupItemEntity(paramGroupCode, true);
        //步骤2.2--根据参数分组中的sql语句查询对象信息
        List<ObjectParamValuesDto> objects = getObjectParamValuesBySql(dbUrl, dbUser, dbPassword, groupDto.getTablecode(), tableColumns, groupDto.getQuerysql(), null, groupDto.getNodes());

        //步骤3--返回结果中的参数项集合处理
        //记录已经加入到返回结果中的参数项编码
        List<String> resultParamItemCode = new ArrayList<>();
        List<ParamItemDto> resultParamItems = new ArrayList<>();
        //先遍历分组的参数项集合，再遍历对象集合将没有在分组参数项中定义的参数名称加入结果
        if (groupItems != null && groupItems.size() > 0x0) {
            for (QcParamItem paramItem : groupItems) {
                resultParamItemCode.add(paramItem.getItemcode());
                resultParamItems.add(ParamItemMapper.MAPPER.toDto(paramItem));
            }
        }
        if (objects != null && objects.size() > 0x0) {
            for (ObjectParamValuesDto objParamValues : objects) {
                if (objParamValues.getValues() != null && objParamValues.getValues().size() > 0x0) {
                    for (String paramKey : objParamValues.getValues().keySet()) {
                        if (!resultParamItemCode.contains(paramKey)) {
                            //当前对象的参数key不在返回结果的参数项中
                            ParamItemDto paramItemDto = new ParamItemDto();
                            //参数项信息仅作为前端显示使用
                            paramItemDto.setItemcode(paramKey);
                            paramItemDto.setName(paramKey);//显示的名称与参数key相同
                            paramItemDto.setDatatype(DataTypeEnum.STRING.getIndex());
                            paramItemDto.setFlag(ResourceStatusFlagEnum.NORMAL.getIndex());

                            resultParamItemCode.add(paramKey);
                            resultParamItems.add(paramItemDto);
                        }
                    }
                }
            }
        }

        //步骤4--返回结果处理
        ParamValuesQueryResultDto result = new ParamValuesQueryResultDto();
        result.setGroup(groupDto);
        result.setItems(resultParamItems);
        result.setObjs(objects);

        return result;
    }

    public String save(ParamValuesSaveDto paramValues) throws QCPromptException, SQLException {
        if (paramValues == null)
            return "保存参数值时对象不能为空";
        if (StringUtils.isBlank(paramValues.getGroupcode()))
            return "保存参数值时指定的参数分组编码不能为空";
        //判断传入的对象集合信息是否为空
        if (paramValues.getObjs() == null || paramValues.getObjs().size() < 0x1)
            return "保存参数值时对象参数值集合不能为空";

        ParamGroupDto groupDto = paramService.getGroup(paramValues.getGroupcode());
        //如果没有分组信息，无法进行后继的信息查询操作
        if (groupDto == null)
            throw new QCPromptException("获取到的参数分组信息为空，输入的参数分组编码错误");
        //如果分组信息中没有查询语句，无法进行对象信息查询
        if (StringUtils.isBlank(groupDto.getQuerysql()))
            throw new QCPromptException("获取到的参数分组信息中查询语句为空，无法进行对象信息和参数值信息查询操作");
        //最终修改对象参数使用的sql语句为：update table set param=? where id=?
        //直接在参数分组表中配置修改sql语句，避免出现还需要查询数据库表和列信息动态构建导致处理过于复杂的问题
        if (StringUtils.isBlank(groupDto.getUpdatesql()))
            throw new QCPromptException("获取到的参数分组信息中修改语句为空，无法进行对象参数值信息设置操作");
        //如果分组信息中没有数据库表编码，无法进行数据库表列信息提取，此时可以使用默认值
        //没有数据库表编码时，无法确定对象表所在的数据库，无法完成对象查询
        if (StringUtils.isBlank(groupDto.getTablecode()))
            throw new QCPromptException("获取到的参数分组信息中数据库表编码为空，无法进行对象信息和参数值信息查询操作");

        //根据数据库表编码获取数据库信息
        DBTableDto tableDto = dbTableService.get(groupDto.getTablecode());
        if (tableDto == null)
            throw new QCPromptException("根据指定的数据库表编码" + groupDto.getTablecode() + "获取到的数据库表信息为空");
        DBDto dbDto = dbService.get(tableDto.getDb());
        if (dbDto == null)
            throw new QCPromptException("根据指定的数据库编码" + tableDto.getDb() + "获取到的数据库信息为空");

        //数据库连接信息
        String dbUrl = "";
        String dbUser = "";
        String dbPassword = "";
        //解析数据库连接信息
        String dbConJsonString = dbDto.getCon();
        if (StringUtils.isNotBlank(dbConJsonString)) {
            //Json对象进行获取
            dbUrl = JsonParserUtil.getString(dbConJsonString, "url");
            dbUser = JsonParserUtil.getString(dbConJsonString, "user");
            dbPassword = JsonParserUtil.getString(dbConJsonString, "password");
        }
        //根据参数分组中的sql语句查询对象信息
        List<Map<String, Object>> queryResult = SqlRunnerUtil.selectAll(dbUrl, dbUser, dbPassword, groupDto.getQuerysql());
        //如果查询对象信息为空，无法进行参数值设置操作；只能使用update语句，不能进行insert操作
        if (queryResult == null || queryResult.size() < 0x1)
            return "根据指定的参数分组查询的对象信息为空，无法进行参数值设置操作";
        //获取对象表中的列名称信息，为后面获取信息做准备
        //查询数据库表列信息，用作分析列名
        List<QcDbTableColumn> tableColumns = dbTableColumnService.getTableColumnEntitys(groupDto.getTablecode(), false,"qrodr");
        String objectIdColumnName = null;
        String objectNameColumnName = null;
        String objectParamColumnName = null;
        QcDbTableColumn objectIdColumn = null;
        QcDbTableColumn objectNameColumn = null;
        //如果有数据库表列信息，从列信息中分析对象id、名称和参数对应的列名
        if (tableColumns != null && tableColumns.size() > 0x0) {
            //如果有配置数据库列信息，从列信息中获取；
            List<QcDbTableColumn> idColumns = tableColumns.stream().filter(p -> p.getColtype() == ColumnTypeEnum.OBJECT_ID).collect(Collectors.toList());
            if (idColumns != null && idColumns.size() > 0x0) {
                objectIdColumn = idColumns.get(0x0);
                objectIdColumnName = objectIdColumn.getCode();
            }
            List<QcDbTableColumn> nameColumns = tableColumns.stream().filter(p -> p.getColtype() == ColumnTypeEnum.OBJECT_NAME).collect(Collectors.toList());
            if (nameColumns != null && nameColumns.size() > 0x0) {
                objectNameColumn = nameColumns.get(0x0);
                objectNameColumnName = objectNameColumn.getCode();
            }
            List<QcDbTableColumn> paramColumns = tableColumns.stream().filter(p -> p.getColtype() == ColumnTypeEnum.PARAM_VALUE).collect(Collectors.toList());
            if (paramColumns != null && paramColumns.size() > 0x0) {
                QcDbTableColumn objectParamColumn = paramColumns.get(0x0);
                objectParamColumnName = objectParamColumn.getCode();
            }
            //根据sql语句得到的结果中可能与数据库表列中配置的大小写不同，获取对象查询结果的第1条记录进行匹配
            Set<String> queryResultFieldNames = queryResult.get(0x0).keySet();
            //根据查询的对象信息结果中返回的列名称进行大小写匹配处理
            for (String fieldName : queryResultFieldNames) {
                if (StringUtils.isNotBlank(objectIdColumnName)) {
                    if (StringUtils.equalsIgnoreCase(fieldName, objectIdColumnName)) {
                        objectIdColumnName = fieldName;
                        continue;
                    }
                }
                if (StringUtils.isNotBlank(objectNameColumnName)) {
                    if (StringUtils.equalsIgnoreCase(fieldName, objectNameColumnName)) {
                        objectNameColumnName = fieldName;
                        continue;
                    }
                }
                if (StringUtils.isNotBlank(objectParamColumnName)) {
                    if (StringUtils.equalsIgnoreCase(fieldName, objectParamColumnName)) {
                        objectParamColumnName = fieldName;
                        continue;
                    }
                }
            }
        }
        //如果根据数据库表列信息得到的id、name、param列名称其中有1个为空，需要从对象参数值查询结果中进行匹配
        if (StringUtils.isBlank(objectIdColumnName) || StringUtils.isBlank(objectNameColumnName) || StringUtils.isBlank(objectParamColumnName)) {
            //取对象参数值查询结果的第一个进行匹配
            Set<String> queryResultFieldNames = queryResult.get(0x0).keySet();
            if (queryResultFieldNames != null && queryResultFieldNames.size() > 0x0) {
                //根据一般的命名进行匹配
                for (String fieldName : queryResultFieldNames) {
                    if (StringUtils.isBlank(objectIdColumnName)) {
                        List<String> list = new ArrayList<>(Arrays.asList(ObjectIdColumnNames));
                        if (list.contains(fieldName)) {
                            objectIdColumnName = fieldName;
                        }
                    }
                    if (StringUtils.isBlank(objectNameColumnName)) {
                        List<String> list = new ArrayList<>(Arrays.asList(ObjectNameColumnNames));
                        if (list.contains(fieldName)) {
                            objectNameColumnName = fieldName;
                        }
                    }
                    if (StringUtils.isBlank(objectParamColumnName)) {
                        List<String> list = new ArrayList<>(Arrays.asList(ObjectParamColumnNames));
                        if (list.contains(fieldName)) {
                            objectParamColumnName = fieldName;
                        }
                    }
                }
                //如果还是没有匹配的，默认按查询结果的顺序进行对应：顺序为：id，name，param
                String[] fieldArray = queryResultFieldNames.toArray(new String[queryResultFieldNames.size()]);
                if (StringUtils.isBlank(objectIdColumnName) && fieldArray.length > 0x0) {
                    objectIdColumnName = fieldArray[0x0];
                }
                if (StringUtils.isBlank(objectNameColumnName) && fieldArray.length > 0x1) {
                    objectNameColumnName = fieldArray[0x1];
                }
                if (StringUtils.isBlank(objectParamColumnName) && fieldArray.length > 0x2) {
                    objectParamColumnName = fieldArray[0x2];
                }
            }
        }
        //如果处理完后还存在id、name、param所对应的列为空，无法进行后继处理
        if (StringUtils.isBlank(objectIdColumnName)) {
            return "根据指定的数据库表编码" + groupDto.getTablecode() + "获取到的对象ID列名为空";
        }
        if (StringUtils.isBlank(objectNameColumnName)) {
            return "根据指定的数据库表编码" + groupDto.getTablecode() + "获取到的对象名称列名为空";
        }
        if (StringUtils.isBlank(objectParamColumnName)) {
            return "根据指定的数据库表编码" + groupDto.getTablecode() + "获取到的对象参数值列名为空";
        }
        //记录参数值操作日志
        List<QcParamValueLog> logs = new ArrayList<>();
        Date now = DateUtil.getNowDate();
        //遍历传入的要保存对象参数值集合信息，逐个进行判断处理
        for (ObjectParamValuesDto objectParamValues : paramValues.getObjs()) {
            //对象参数值信息不能为空，对象ID/编码不能为空，参数值集合不能为空（如果为删除也需要有key）
            if (objectParamValues != null && StringUtils.isNotBlank(objectParamValues.getObjcode()) && objectParamValues.getValues() != null && objectParamValues.getValues().size() > 0x0) {
                String objCode = objectParamValues.getObjcode();
                String objParamValueString = null;
                //保存参数会有不同的情况：新增参数值--原来参数值json为空，需要创建json对象并进行赋值后保持；修改/删除参数值--原来参数值json不为空，需要对指定的json节点的值进行修改；
                //从对象参数值表查询结果中获取当前对象的参数值json字符串
                for (Map<String, Object> queryResultItem : queryResult) {
                    Object objId = queryResultItem.get(objectIdColumnName);
                    if (objId != null && StringUtils.equalsIgnoreCase(objId.toString(), objCode)) {
                        Object objParamValue = queryResultItem.get(objectParamColumnName);
                        if (objParamValue != null)
                            objParamValueString = objParamValue.toString();
                        //在查询结果中找到当前对象ID后跳出循环
                        break;
                    }
                }
                System.out.println("处理 objCode=" + objCode + " 得到的objParamValueString=" + objParamValueString);
                //使用 JSONObject的put方法 添加或替换 key 对应的 value
                JSONObject jsonObject = JsonUtil.toJSONObject(objParamValueString);
                //如果根据json字符串解析的json对象为空，创建一个新的json对象
                if (jsonObject == null)
                    jsonObject = new JSONObject();
                //以传入要设置的参数键值对为准进行遍历修改--遍历参数分组中的参数值节点，每个节点的名称如果在传入的参数键值对中时进行赋值
                //参数分组中的参数值节点可以设置为一个或多个，需要逐个进行遍历并解析出json节点
                //获取对象参数值节点可以有多个，需要分解后逐个得到要获取的参数值节点信息
                //如果指定要返回的参数节点为空，或者指定的错误，返回参数值的所有第一级节点参数值
                String[] paramNodeNames = StringSplitUtil.Split(groupDto.getNodes(), true);
                //判断解析指定的参数节点字符串集合，如果为空表示获取第一级节点
                if (paramNodeNames == null || paramNodeNames.length < 0x1) {
                    //指定的参数节点为空，或者指定的参数节点信息解析后无有效值
                    //固定设置为*，方便下面的统一遍历处理
                    paramNodeNames = new String[]{QCConstant.ALL_STRING};
                }
                //逐个遍历参数节点进行解析获取
                for (String paramNodeName : paramNodeNames) {
                    String[] childStrs = StringSplitUtil.Split(paramNodeName, QCConstant.CHILD_STRING, true);
                    //解析父子级信息：如果得到的数组长度为1表示没有父子级信息，如果数组长度大于1表示有父子级信息--从第1级开始向子级逐级进行选取直到数组的倒数1个元素
                    if (childStrs != null && childStrs.length > 0x1) {
                        //按父子级关系选择json节点至数组中的倒数第1个节点
                        //jsonObject的根节点对象，用于记录和更新节点信息，方便信息更新后替换回jsonObject
                        //选择节点--进行判断节点是否存在需要从上到下进行逐级选择；对不存在的节点进行创建后修改json对象需要从下到上逐级进行赋值
                        //记录父子级节点每级是否存在，索引从0开始
                        List<Boolean> nodeLevelAndExist = new ArrayList<>();
                        List<String> nodeLevelAndJsonStrs = new ArrayList<>();
                        JSONObject parentNodeJsonObject = jsonObject;
                        for (int i = 0; i < childStrs.length - 1; i++) {
                            boolean currentNodeExist = false;
                            if (parentNodeJsonObject != null) {
                                JSONObject currentNodeJsonObject = parentNodeJsonObject.getJSONObject(childStrs[i]);
                                if (currentNodeJsonObject != null) {
                                    currentNodeExist = true;
                                    parentNodeJsonObject = currentNodeJsonObject;
                                } else {
                                    currentNodeExist = false;
                                    parentNodeJsonObject = null;
                                }
                            }
                            nodeLevelAndExist.add(currentNodeExist);
                            nodeLevelAndJsonStrs.add(currentNodeExist ? parentNodeJsonObject.toJSONString() : null);
                        }
                        for (int i = 0; i < nodeLevelAndExist.size(); i++) {
                            System.out.println("处理 paramNodeName=" + paramNodeName + " level=" + i + " exist=" + nodeLevelAndExist.get(i) + " json=" + nodeLevelAndJsonStrs.get(i));
                        }
                        //根据记录的每个层级的节点是否存在进行处理，需要从最下一级开始处理
                        //从第一个不存在的节点层级开始，已经存在节点的逐个进行获取信息
                        //对最末级的节点进行赋值，如果之前循环得到的parentNodeJsonObject不为空则该对象为最末级的节点对象，如果为空则新创建一个json对象
                        JSONObject destNodeJsonObject = parentNodeJsonObject == null ? new JSONObject() : parentNodeJsonObject;
                        //逐个遍历获取传入的要设置的参数值键值对，对最末级节点进行赋值
                        //遍历传入的要设置的参数值的键值对，逐个对当前选择的json节点进行赋值；使用put方法完成不存在的节点新增，存在的节点修改值操作
                        for (Map.Entry<String, Object> entry : objectParamValues.getValues().entrySet()) {
                            if (StringUtils.isNotBlank(entry.getKey())) {
                                //日志记录
                                QcParamValueLog log = new QcParamValueLog();
                                log.setGroupcode(groupDto.getCode());
                                //日志中记录的参数项编码--记录节点关系
                                log.setNodestr(paramNodeName.substring(0x0, paramNodeName.indexOf(QCConstant.CHILD_STRING)));
                                log.setParamname(entry.getKey());
                                log.setObjcode(objCode);
                                log.setTm(now);
                                log.setOptype(DataValueOperateTypeEnum.INSERT);
                                //如果已存在节点信息，获取原来的值
                                if (parentNodeJsonObject != null) {
                                    Object beforeValueObject = destNodeJsonObject.get(entry.getKey());
                                    if (beforeValueObject != null) {
                                        log.setOptype(DataValueOperateTypeEnum.UPDATE);
                                        log.setBeforeval(beforeValueObject.toString());
                                    }
                                }
                                if (entry.getValue() != null)
                                    log.setAfterval(entry.getValue().toString());

                                //判断如果新旧2个值相同，不进行日志记录
                                if (StringUtils.isBlank(log.getBeforeval()) || StringUtils.isBlank(log.getAfterval()) || !StringUtils.equalsIgnoreCase(log.getBeforeval(), log.getAfterval()))
                                    logs.add(log);

                                //赋值放到最后，解决获取原来的值错误的问题
                                destNodeJsonObject.put(entry.getKey(), entry.getValue());
                            }
                        }
                        System.out.println("处理 paramNodeName=" + paramNodeName + " 对参数值进行修改后，得到的节点destNodeJsonObject=" + destNodeJsonObject.toJSONString());
                        //将设置的参数值赋值到json对象：需要从最末级的节点逐个向上；最末级的已经在上面处理，不需要重复处理；根节点第一级在循环外处理，因此i不能等于0
                        JSONObject parentLevelNodeJsonObject = null;
                        for (int i = nodeLevelAndExist.size() - 1; i > 0; i--) {
                            System.out.println("处理 paramNodeName=" + paramNodeName + " 中对应节点的值， level=" + i + " exist=" + nodeLevelAndExist.get(i) + " json=" + nodeLevelAndJsonStrs.get(i));
                            //当前节点Json对象，如果当前节点不存在创建新的json对象，如果当前节点存在则使用json字符串解析得到json对象
                            JSONObject currentNodeJsonObject = nodeLevelAndExist.get(i) ? JsonUtil.toJSONObject(nodeLevelAndJsonStrs.get(i)) : new JSONObject();
                            //对当前节点中下级节点进行赋值，如果记录的赋值结果对象（下一级节点）为空则使用最末级的目标节点，如果不为空使用前一次得到的结果
                            currentNodeJsonObject.put(childStrs[i], parentLevelNodeJsonObject == null ? destNodeJsonObject : parentLevelNodeJsonObject);
                            //更新记录的层级节点对象信息
                            parentLevelNodeJsonObject = currentNodeJsonObject;
                        }
                        //对参数值json对象的根节点进行赋值
                        jsonObject.put(childStrs[0x0], parentLevelNodeJsonObject == null ? destNodeJsonObject : parentLevelNodeJsonObject);
                        System.out.println("处理 paramNodeName=" + paramNodeName + " 对参数值进行修改后，得到的节点json=" + jsonObject.toJSONString());
                    } else {
                        //没有父子级关系，当前所有参数均在根节点下
                        for (Map.Entry<String, Object> entry : objectParamValues.getValues().entrySet()) {
                            if (StringUtils.isNotBlank(entry.getKey())) {
                                //日志记录，只有根节点数据，要在对jsonObject修改之前处理日志信息，在修改之后获取到的原参数值不对
                                QcParamValueLog log = new QcParamValueLog();
                                log.setGroupcode(groupDto.getCode());
                                //日志中记录的参数项编码--记录节点关系
                                //全部都在根节点下，设置节点字符串为空
                                log.setNodestr(null);
                                log.setParamname(entry.getKey());
                                log.setObjcode(objCode);
                                log.setTm(now);
                                log.setOptype(DataValueOperateTypeEnum.INSERT);
                                //如果当前赋值为空，设置为删除参数??
                                //如果已存在节点信息，获取原来的值
                                if (jsonObject != null) {
                                    Object beforeValueObject = jsonObject.get(entry.getKey());
                                    if (beforeValueObject != null) {
                                        log.setOptype(DataValueOperateTypeEnum.UPDATE);
                                        log.setBeforeval(beforeValueObject.toString());
                                    }
                                }
                                if (entry.getValue() != null)
                                    log.setAfterval(entry.getValue().toString());
                                //判断如果新旧2个值相同，不进行日志记录
                                if (StringUtils.isBlank(log.getBeforeval()) || StringUtils.isBlank(log.getAfterval()) || !StringUtils.equalsIgnoreCase(log.getBeforeval(), log.getAfterval()))
                                    logs.add(log);

                                //只有根节点，直接对jsonObject进行修改
                                //赋值放到最后，解决获取原来的值错误的问题
                                jsonObject.put(entry.getKey(), entry.getValue());
                            }
                        }
                    }
                }
                System.out.println("处理 objCode=" + objCode + " 对参数值进行修改后，得到的objParamValueString=" + jsonObject.toJSONString());
                //执行update语句，参数1为参数值json字符串，参数2为对象ID/编码
                boolean updateSqlResult = SqlRunnerUtil.update(dbUrl, dbUser, dbPassword, groupDto.getUpdatesql(), jsonObject.toJSONString(), objCode);
                if (updateSqlResult == false)
                    return "修改对象ID/编码为：" + objCode + "的参数值时执行更新操作失败";
            }
        }
        //日志信息记录
        if (logs != null && logs.size() > 0x0) {
            paramValueLogService.batchSaveLogs(logs);
        }

        return null;
    }

    /***
     * 根据指定条件查询对象的参数值信息
     *
     * @param condition 查询条件，指定数据库表编码、对象ID/编码、参数名称、返回结果是指定节点还是下一级节点
     * @return java.util.List<qc.module.platform.dto.param.value.ObjectParamValuesDto>
     * @author QuCheng Tech
     * @since 2024/2/23
     */
    public List<ObjectParamValuesDto> getValues(ParamValuesGetConditionDto condition) throws QCPromptException, SQLException {
        //获取参数值的条件中数据库表编码、对象ID必须指定
        if (condition == null)
            throw new QCPromptException("获取参数值信息时，获取条件不能为空");
        if (StringUtils.isBlank(condition.getTablecode()))
            throw new QCPromptException("获取参数值信息时，必须指定数据库表编码");
        if (StringUtils.isBlank(condition.getObjectids()))
            throw new QCPromptException("获取参数值信息时，必须指定对象ID/编码");
        //分解对象ID/编码
        String[] objectIds = StringSplitUtil.Split(condition.getObjectids(), true);
        if (objectIds == null || objectIds.length < 0x1)
            throw new QCPromptException("获取参数值信息时，无有效的对象ID/编码");
        //根据数据库表编码获取数据库信息
        DBTableDto tableDto = dbTableService.get(condition.getTablecode());
        if (tableDto == null)
            throw new QCPromptException("根据指定的数据库表编码" + condition.getTablecode() + "获取到的数据库表信息为空");
        DBDto dbDto = dbService.get(tableDto.getDb());
        if (dbDto == null)
            throw new QCPromptException("根据指定的数据库编码" + tableDto.getDb() + "获取到的数据库信息为空");

        //数据库连接信息
        String dbUrl = "";
        String dbUser = "";
        String dbPassword = "";
        //解析数据库连接信息
        String dbConJsonString = dbDto.getCon();
        if (StringUtils.isNotBlank(dbConJsonString)) {
            //Json对象进行获取
            dbUrl = JsonParserUtil.getString(dbConJsonString, "url");
            dbUser = JsonParserUtil.getString(dbConJsonString, "user");
            dbPassword = JsonParserUtil.getString(dbConJsonString, "password");
        }

        //根据数据库表编码进行对象和参数信息查询：
        //分为有数据库表列信息--可以根据配置的数据库表列构造查询语句；
        //   无有效的数据库表列信息--固定查询表中的全部，再根据查询结果进行解析
        String objectIdColumnName = null;
        String objectNameColumnName = null;
        String objectParamColumnName = null;
        //查询数据库表的列信息
        List<QcDbTableColumn> tableColumns = dbTableColumnService.getTableColumnEntitys(condition.getTablecode(), false,"qrodr");
        if (tableColumns != null && tableColumns.size() > 0x0) {
            //如果有配置数据库列信息，从列信息中获取；
            List<QcDbTableColumn> idColumns = tableColumns.stream().filter(p -> p.getColtype() == ColumnTypeEnum.OBJECT_ID).collect(Collectors.toList());
            if (idColumns != null && idColumns.size() > 0x0) {
                QcDbTableColumn objectIdColumn = idColumns.get(0x0);
                objectIdColumnName = objectIdColumn.getCode();
            }
            List<QcDbTableColumn> nameColumns = tableColumns.stream().filter(p -> p.getColtype() == ColumnTypeEnum.OBJECT_NAME).collect(Collectors.toList());
            if (nameColumns != null && nameColumns.size() > 0x0) {
                QcDbTableColumn objectNameColumn = nameColumns.get(0x0);
                objectNameColumnName = objectNameColumn.getCode();
            }
            List<QcDbTableColumn> paramColumns = tableColumns.stream().filter(p -> p.getColtype() == ColumnTypeEnum.PARAM_VALUE).collect(Collectors.toList());
            if (paramColumns != null && paramColumns.size() > 0x0) {
                QcDbTableColumn objectParamColumn = paramColumns.get(0x0);
                objectParamColumnName = objectParamColumn.getCode();
            }

        }
        //如果对象id、名称、参数列名称其中任意一个在数据库表列中没有配置，使用查询对象信息结果进行再次匹配
        if (StringUtils.isBlank(objectIdColumnName) || StringUtils.isBlank(objectNameColumnName) || StringUtils.isBlank(objectParamColumnName)) {
            //因为不确定数据库表中的列名，无法指定列进行查询，因此使用sql语句为：select * from tablecode
            String sql = "select * from " + condition.getTablecode();
            //如果已有确定对象id列名，加上过滤条件
            String querySqlIdConditionValue = null;
            if (StringUtils.isNotBlank(objectIdColumnName)) {
                if (objectIds.length == 0x1) {
                    sql += " where " + objectIdColumnName + " =?";
                    querySqlIdConditionValue = objectIds[0x0];
                } else {
                    sql += " where " + objectIdColumnName + " in (?)";
                    StringBuilder sb = new StringBuilder();
                    for (String id : objectIds) {
                        sb.append(id + ",");
                    }
                    //移除最后的逗号
                    sb.deleteCharAt(sb.length() - 1);
                    querySqlIdConditionValue = sb.toString();
                }
            }

            Map<String, Object> queryResult = SqlRunnerUtil.selectOne(dbUrl, dbUser, dbPassword, sql, querySqlIdConditionValue);
            if (queryResult != null && queryResult.size() > 0x0) {
                //根据sql语句得到的结果中可能与数据库表列中配置的大小写不同，获取对象查询结果的第1条记录进行匹配
                Set<String> queryResultFieldNames = queryResult.keySet();
                //根据查询的对象信息结果中返回的列名称进行大小写匹配处理
                for (String fieldName : queryResultFieldNames) {
                    if (StringUtils.isNotBlank(objectIdColumnName)) {
                        if (StringUtils.equalsIgnoreCase(fieldName, objectIdColumnName)) {
                            objectIdColumnName = fieldName;
                            continue;
                        }
                    }
                    if (StringUtils.isNotBlank(objectNameColumnName)) {
                        if (StringUtils.equalsIgnoreCase(fieldName, objectNameColumnName)) {
                            objectNameColumnName = fieldName;
                            continue;
                        }
                    }
                    if (StringUtils.isNotBlank(objectParamColumnName)) {
                        if (StringUtils.equalsIgnoreCase(fieldName, objectParamColumnName)) {
                            objectParamColumnName = fieldName;
                            continue;
                        }
                    }
                }
            }
        }

        //如果根据数据库表列信息和对象查询结果处理后id、名称、参数列中还有不确定的列，无法进行后继的处理
        if (StringUtils.isBlank(objectIdColumnName))
            throw new QCPromptException("获取参数值信息时，无有效的对象ID/编码列名");
        if (StringUtils.isBlank(objectNameColumnName))
            throw new QCPromptException("获取参数值信息时，无有效的对象名称列名");
        if (StringUtils.isBlank(objectParamColumnName))
            throw new QCPromptException("获取参数值信息时，无有效的对象参数列名");

        //根据列名构造查询参数值的sql语句和对象条件值
        String sql = "select " + objectIdColumnName + "," + objectNameColumnName + "," + objectParamColumnName + " from " + condition.getTablecode();
        //如果已有确定对象id列名，加上过滤条件
        String querySqlIdConditionValue = null;
        if (StringUtils.isNotBlank(objectIdColumnName)) {
            if (objectIds.length == 0x1) {
                sql += " where " + objectIdColumnName + " =?";
                querySqlIdConditionValue = objectIds[0x0];
            } else {
                sql += " where " + objectIdColumnName + " in (?)";
                StringBuilder sb = new StringBuilder();
                for (String id : objectIds) {
                    sb.append(id + ",");
                }
                //移除最后的逗号
                sb.deleteCharAt(sb.length() - 1);
                querySqlIdConditionValue = sb.toString();
            }
        }

        //获取对象参数值信息
        return getObjectParamValuesBySql(dbUrl, dbUser, dbPassword, condition.getTablecode(), tableColumns, sql, querySqlIdConditionValue, condition.getParamnodes());
    }

    /***
     * 根据指定的查询对象信息sql语句进行对象信息查询
     *
     * @param dbUrl 数据库url
     * @param dbUser 数据库用户名
     * @param dbPassword 数据库密码
     * @param tableCode 数据库表编码
     * @param tableColumns 数据库表列信息，可以为空
     * @param sql 查询sql语句
     * @param sqlObjectIds 查询sql语句中的对象ID值，可以为空
     * @param paramNodes 参数节点；可以为空、可以为多个；多个之间使用逗号分隔，每个中使用大于符号＞指定上下级关系；
     * @return java.util.List<qc.module.platform.dto.param.value.ObjectParamValuesDto>
     * @author QuCheng Tech
     * @since 2024/2/21
     */
    List<ObjectParamValuesDto> getObjectParamValuesBySql(String dbUrl, String dbUser, String dbPassword,
                                                         String tableCode, List<QcDbTableColumn> tableColumns,
                                                         String sql, String sqlObjectIds,
                                                         String paramNodes) throws SQLException, QCPromptException {
        List<Map<String, Object>> queryResult = null;
        if (StringUtils.isBlank(sqlObjectIds))
            queryResult = SqlRunnerUtil.selectAll(dbUrl, dbUser, dbPassword, sql);
        else
            queryResult = SqlRunnerUtil.selectAll(dbUrl, dbUser, dbPassword, sql, sqlObjectIds);
        if (queryResult != null && queryResult.size() > 0x0) {
            //查询结果转换处理
            //需要从查询的结果中按列名区分出id、name、param
            String objectIdColumnName = null;
            String objectNameColumnName = null;
            String objectParamColumnName = null;
            QcDbTableColumn objectIdColumn = null;
            QcDbTableColumn objectNameColumn = null;
            //如果有数据库表列信息，从列信息中分析对象id、名称和参数对应的列名
            if (tableColumns != null && tableColumns.size() > 0x0) {
                //如果有配置数据库列信息，从列信息中获取；
                List<QcDbTableColumn> idColumns = tableColumns.stream().filter(p -> p.getColtype() == ColumnTypeEnum.OBJECT_ID).collect(Collectors.toList());
                if (idColumns != null && idColumns.size() > 0x0) {
                    objectIdColumn = idColumns.get(0x0);
                    objectIdColumnName = objectIdColumn.getCode();
                }
                List<QcDbTableColumn> nameColumns = tableColumns.stream().filter(p -> p.getColtype() == ColumnTypeEnum.OBJECT_NAME).collect(Collectors.toList());
                if (nameColumns != null && nameColumns.size() > 0x0) {
                    objectNameColumn = nameColumns.get(0x0);
                    objectNameColumnName = objectNameColumn.getCode();
                }
                List<QcDbTableColumn> paramColumns = tableColumns.stream().filter(p -> p.getColtype() == ColumnTypeEnum.PARAM_VALUE).collect(Collectors.toList());
                if (paramColumns != null && paramColumns.size() > 0x0) {
                    QcDbTableColumn objectParamColumn = paramColumns.get(0x0);
                    objectParamColumnName = objectParamColumn.getCode();
                }
                //根据sql语句得到的结果中可能与数据库表列中配置的大小写不同，获取对象查询结果的第1条记录进行匹配
                Set<String> queryResultFieldNames = queryResult.get(0x0).keySet();
                //根据查询的对象信息结果中返回的列名称进行大小写匹配处理
                for (String fieldName : queryResultFieldNames) {
                    if (StringUtils.isNotBlank(objectIdColumnName)) {
                        if (StringUtils.equalsIgnoreCase(fieldName, objectIdColumnName)) {
                            objectIdColumnName = fieldName;
                            continue;
                        }
                    }
                    if (StringUtils.isNotBlank(objectNameColumnName)) {
                        if (StringUtils.equalsIgnoreCase(fieldName, objectNameColumnName)) {
                            objectNameColumnName = fieldName;
                            continue;
                        }
                    }
                    if (StringUtils.isNotBlank(objectParamColumnName)) {
                        if (StringUtils.equalsIgnoreCase(fieldName, objectParamColumnName)) {
                            objectParamColumnName = fieldName;
                            continue;
                        }
                    }
                }
            }
            //如果根据数据库表列信息得到的id、name、param列名称其中有1个为空，需要从对象参数值查询结果中进行匹配
            if (StringUtils.isBlank(objectIdColumnName) || StringUtils.isBlank(objectNameColumnName) || StringUtils.isBlank(objectParamColumnName)) {
                //取对象参数值查询结果的第一个进行匹配
                Set<String> queryResultFieldNames = queryResult.get(0x0).keySet();
                if (queryResultFieldNames != null && queryResultFieldNames.size() > 0x0) {
                    //根据一般的命名进行匹配
                    for (String fieldName : queryResultFieldNames) {
                        if (StringUtils.isBlank(objectIdColumnName)) {
                            List<String> list = new ArrayList<>(Arrays.asList(ObjectIdColumnNames));
                            if (list.contains(fieldName)) {
                                objectIdColumnName = fieldName;
                            }
                        }
                        if (StringUtils.isBlank(objectNameColumnName)) {
                            List<String> list = new ArrayList<>(Arrays.asList(ObjectNameColumnNames));
                            if (list.contains(fieldName)) {
                                objectNameColumnName = fieldName;
                            }
                        }
                        if (StringUtils.isBlank(objectParamColumnName)) {
                            List<String> list = new ArrayList<>(Arrays.asList(ObjectParamColumnNames));
                            if (list.contains(fieldName)) {
                                objectParamColumnName = fieldName;
                            }
                        }
                    }
                    //如果还是没有匹配的，默认按查询结果的顺序进行对应：顺序为：id，name，param
                    String[] fieldArray = queryResultFieldNames.toArray(new String[queryResultFieldNames.size()]);
                    if (StringUtils.isBlank(objectIdColumnName) && fieldArray.length > 0x0) {
                        objectIdColumnName = fieldArray[0x0];
                    }
                    if (StringUtils.isBlank(objectNameColumnName) && fieldArray.length > 0x1) {
                        objectNameColumnName = fieldArray[0x1];
                    }
                    if (StringUtils.isBlank(objectParamColumnName) && fieldArray.length > 0x2) {
                        objectParamColumnName = fieldArray[0x2];
                    }
                }
            }
            //如果处理完后还存在id、name、param所对应的列为空，无法进行后继处理
            if (StringUtils.isBlank(objectIdColumnName)) {
                throw new QCPromptException("根据指定的数据库表编码" + tableCode + "获取到的对象ID列名为空");
            }
            if (StringUtils.isBlank(objectNameColumnName)) {
                throw new QCPromptException("根据指定的数据库表编码" + tableCode + "获取到的对象名称列名为空");
            }
            if (StringUtils.isBlank(objectParamColumnName)) {
                throw new QCPromptException("根据指定的数据库表编码" + tableCode + "获取到的对象参数值列名为空");
            }

            System.out.println("ParamValueService getObjectParamValuesBySql 获取对象信息使用的列名称为：objectIdColumnName=" + objectIdColumnName + " objectNameColumnName=" + objectNameColumnName + " objectParamColumnName=" + objectParamColumnName);

            //遍历查询的对象结果集进行处理
            List<ObjectParamValuesDto> result = new ArrayList<>();
            //获取对象参数值节点可以有多个，需要分解后逐个得到要获取的参数值节点信息
            //如果指定要返回的参数节点为空，或者指定的错误，返回参数值的所有第一级节点参数值
            String[] paramNodeNames = StringSplitUtil.Split(paramNodes, true);
            //判断解析指定的参数节点字符串集合，如果为空表示获取第一级节点
            if (paramNodeNames == null || paramNodeNames.length < 0x1) {
                //指定的参数节点为空，或者指定的参数节点信息解析后无有效值
                //固定设置为*，方便下面的统一遍历处理
                paramNodeNames = new String[]{QCConstant.ALL_STRING};
            }

            for (Map<String, Object> row : queryResult) {
                for (String key : row.keySet()) {
                    Object objValue = row.get(key);
                    System.out.println("ParamValueService getObjectParamValuesBySql 遍历对象处理参数值信息 key=" + key + " value=" + objValue.toString());
                }
                //使用row.get方法需要指定的key大小写相同，根据sql语句得到的结果中可能与数据库表列中配置的大小写不同，在前面进行处理
                String objId = row.get(objectIdColumnName).toString();
                String objName = row.get(objectNameColumnName).toString();
                String objParamValueJsonString = row.get(objectParamColumnName).toString();

                //定义当前对象的参数值json字符串和参数值集合
                HashMap<String, String> objJsonStrs = new HashMap<>();
                HashMap<String, Object> objParamValues = new HashMap<>();

                //逐个遍历参数节点进行解析获取
                for (String paramNodeName : paramNodeNames) {
                    if (StringUtils.isNotBlank(paramNodeName)) {
                        String[] childStrs = StringSplitUtil.Split(paramNodeName.trim(), QCConstant.CHILD_STRING, true);
                        String nodeParamValueString = null;
                        //解析json字符串进行遍历处理，要对象的参数值json字符串不为空
                        if (StringUtils.isNotBlank(objParamValueJsonString)) {
                            JSONObject jsonObject = JsonUtil.toJSONObject(objParamValueJsonString);
                            //解析父子级信息：如果得到的数组长度为1表示没有父子级信息，如果数组长度大于1表示有父子级信息--从第1级开始向子级逐级进行选取直到数组的倒数1个元素
                            if (childStrs != null && childStrs.length > 0x1) {
                                //按父子级关系选择json节点至数组中的倒数第1个节点
                                for (int i = 0; i < childStrs.length - 1; i++) {
                                    if (jsonObject == null)
                                        break;
                                    jsonObject = jsonObject.getJSONObject(childStrs[i]);
                                }
                            }
                            //判断父子级数组的最后一个元素：是否为星号*、或者包含星号*；只要有星号都认为是节点的所有元素
                            //否则使用同级连接字符串&进行分解
                            String lastChildStr = childStrs[childStrs.length - 1];
                            //使用同级连接符号进行分隔
                            String[] destNodeNames = null;
                            //如果指定的不是查询所有节点，对目标参数名称集合进行分隔赋值
                            if (!StringUtils.contains(lastChildStr, QCConstant.ALL_STRING))
                                destNodeNames = StringSplitUtil.Split(lastChildStr, QCConstant.BROTHER_CONCAT_STRING, true);
                            //如果按父子级关系得到的json节点对象不为空，处理选取参数值的节点信息
                            if (jsonObject != null) {
                                //按父子级关系选择的参数节点有效，对json字符串进行赋值，方面后面使用
                                nodeParamValueString = jsonObject.toJSONString();
                                HashMap<String, Object> paramValues = null;
                                if (StringUtils.contains(lastChildStr, QCConstant.ALL_STRING)) {
                                    //含有星号*，选择节点的所有下级元素
                                    paramValues = JsonParserUtil.getChildKeyValues(nodeParamValueString, null);
                                } else {
                                    if (destNodeNames != null && destNodeNames.length > 0x0) {
                                        paramValues = JsonParserUtil.getKeyValues(jsonObject, destNodeNames);
                                    }
                                }
                                //根据从json对象中获取的参数值结果进行转换处理
                                if (paramValues != null && paramValues.size() > 0x0) {
                                    for (Map.Entry<String, Object> entry : paramValues.entrySet()) {
                                        if (StringUtils.isNotBlank(entry.getKey()))
                                            objParamValues.put(entry.getKey().trim(), entry.getValue().toString());
                                    }
                                }
                            } else {
                                //根据父子级关系选取到的json对象为空，如果指定了参数名称，根据参数名称逐个赋空值
                                if (destNodeNames != null && destNodeNames.length > 0x0) {
                                    for (String name : destNodeNames) {
                                        if (StringUtils.isNotBlank(name))
                                            objParamValues.put(name.trim(), null);
                                    }
                                }
                            }
                        }

                        objJsonStrs.put(paramNodeName.trim(), nodeParamValueString);
                    }
                }

                //当前对象信息和对象参数值信息
                ObjectParamValuesDto obj = new ObjectParamValuesDto();
                obj.setObjcode(objId);
                obj.setObjname(objName);
                obj.setJsonstrs(objJsonStrs);
                obj.setValues(objParamValues);
                result.add(obj);
            }

            return result;
        }

        return null;
    }

    /**
     * 查询日志
     * @param condition 查询日志条件
     * @return 参数值日志查询结果
     * @throws QCPromptException
     * @author QuCheng Tech
     * @since 2024/3/14
     */
    public ParamValueLogQueryResultDto queryLogs(ParamValueLogQueryConditionDto condition) throws QCPromptException, SQLException {
        // 1.判断查询条件
        if (StringUtils.isBlank(condition.getGroupcode())) throw new QCPromptException("分组编码不能为空");
        if (StringUtils.isBlank(condition.getObjectid())) throw new QCPromptException("对象ID/编码不能为空");
        
        // 2.判断分组编码是否存在
        if (Objects.isNull(groupRepository.selectById(condition.getGroupcode()))) 
            throw new QCPromptException("分组编码不存在");
        
        // 3.获取指定对象ID/编码的对象名称
        // 3.1 根据分组编码获取分组信息，从分组信息中取出数据库表编码
        ParamGroupDto groupDto = paramService.getGroup(condition.getGroupcode());
        String tableCode = groupDto.getTablecode();
        // 3.2 根据数据库表编码和对象ID/编码查询指定参数值对象，从中获取对象名称
        String objName = "";
        ParamValuesGetConditionDto con = new ParamValuesGetConditionDto();
        con.setTablecode(tableCode);
        con.setObjectids(condition.getObjectid());
        List<ObjectParamValuesDto> paramValuesDtos = getValues(con);
        if (CollectionUtils.isNotEmpty(paramValuesDtos)){
            for (ObjectParamValuesDto paramValue : paramValuesDtos){
                if (paramValue.getObjcode().equals(condition.getObjectid())){
                    objName = paramValue.getObjname();
                }
            }
        }
        
        // 4.构建查询参数项的查询条件
        LambdaQueryWrapper<QcParamItem> itemWrapper = new LambdaQueryWrapper<>();
        itemWrapper.eq(QcParamItem::getGroupcode,condition.getGroupcode());
        itemWrapper.orderByAsc(QcParamItem::getOdr);
        
        // 5.构建查询参数日志的查询条件
        LambdaQueryWrapper<QcParamValueLog> logWrapper = new LambdaQueryWrapper<>();
        logWrapper.eq(QcParamValueLog::getGroupcode,condition.getGroupcode());
        logWrapper.eq(QcParamValueLog::getObjcode,condition.getObjectid());
        logWrapper.orderByDesc(QcParamValueLog::getTm);
        
        // 6.如果参数编码不为空，设置查询参数项和参数日志的查询条件
        if (StringUtils.isNotBlank(condition.getItemids())){
            itemWrapper.eq(QcParamItem::getItemcode,condition.getItemids());
            logWrapper.eq(QcParamValueLog::getParamname,condition.getItemids());
        }

        // 7.查询指定条件的参数项和参数日志，设置返回结果
        ParamValueLogQueryResultDto resultDto = new ParamValueLogQueryResultDto();
        List<QcParamItem> items = repository.selectList(itemWrapper);
        if (CollectionUtils.isNotEmpty(items)) resultDto.setItems(ParamItemMapper.MAPPER.toDtoList(items));
        
        List<QcParamValueLog> logs = paramValueLogRepository.selectList(logWrapper);
        if (CollectionUtils.isNotEmpty(logs)){
            List<ParamValueLogDto> logDtos = ParamValueLogMapper.MAPPER.toDtoList(logs);
            //设置对象名称
            for (ParamValueLogDto logDto : logDtos){
                logDto.setObjname(objName);
            }
            resultDto.setLogs(logDtos);
        }
        return resultDto;
    }
}
